import sys
import cv2
# import mediapipe
import pyttsx3
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap


class PostureChecker(QThread):
    """
    后台线程用于实时检测坐姿并更新图像
    """
    update_frame = pyqtSignal(QImage)  # 信号，用于更新图像
    posture_status = pyqtSignal(str)  # 信号，用于更新坐姿状态

    def __init__(self):
        super().__init__()
        self.active = True  # 用于控制线程的运行状态
        self.engine = pyttsx3.init()  # 初始化语音引擎

        # # 初始化 MediaPipe 姿态检测模块
        # self.mp_pose = mediapipe.solutions.pose
        # self.pose = self.mp_pose.Pose(model_complexity=1, min_detection_confidence=0.5, min_tracking_confidence=0.5)
        # self.mp_drawing = mediapipe.solutions.drawing_utils

    def run(self):
        """
        线程的主运行函数，用于实时处理摄像头图像并检测坐姿
        """
        cap = cv2.VideoCapture(0)  # 打开摄像头
        while self.active:
            ret, frame = cap.read()  # 读取摄像头帧
            self.sleep(1)
            if not ret:
                self.posture_status.emit("未检测到摄像头")  # 提示未检查到设想头
                continue  # 如果读取失败，则退出循环

            # 将图像转换为 PyQt 可用的格式
            h, w, ch = frame.shape
            bytes_per_line = ch * w
            convert_to_Qt_format = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888).rgbSwapped()
            p = convert_to_Qt_format.scaled(640, 480, Qt.KeepAspectRatio)  # 缩放图像以适应 UI
            self.update_frame.emit(p)  # 发送图像信号
            self.posture_status.emit("坐姿良好")
            continue

            # 将图像从 BGR 转换为 RGB，因为 MediaPipe 需要 RGB 格式
            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = self.pose.process(rgb_frame)  # 使用 MediaPipe 检测姿态

            # 在图像上绘制关键点和连接线
            if results.pose_landmarks:
                self.mp_drawing.draw_landmarks(frame, results.pose_landmarks, self.mp_pose.POSE_CONNECTIONS)
                posture_status = self.check_posture(results.pose_landmarks)  # 检测坐姿
                self.posture_status.emit(posture_status)  # 发送坐姿状态信号

                # 如果坐姿不正确，发出语音提示
                if posture_status != "坐姿良好":
                    self.engine.say(posture_status)
                    self.engine.runAndWait()

        cap.release()  # 释放摄像头资源

    def check_posture(self, landmarks):
        """
        检测坐姿是否正确
        :param landmarks: MediaPipe 检测到的人体关键点
        :return: 坐姿状态描述
        """
        if not landmarks:
            return "未检测到人体"  # 如果未检测到人体关键点，返回提示信息

        # 获取关键点坐标
        left_shoulder = landmarks.landmark[self.mp_pose.PoseLandmark.LEFT_SHOULDER]
        right_shoulder = landmarks.landmark[self.mp_pose.PoseLandmark.RIGHT_SHOULDER]
        left_hip = landmarks.landmark[self.mp_pose.PoseLandmark.LEFT_HIP]
        right_hip = landmarks.landmark[self.mp_pose.PoseLandmark.RIGHT_HIP]

        # 检测肩膀是否水平
        shoulder_diff = abs(left_shoulder.y - right_shoulder.y)
        print("肩膀不水平，请调整坐姿=", shoulder_diff)
        if shoulder_diff > 0.05:  # 肩膀倾斜阈值
            return "肩膀不水平，请调整坐姿"

        # 检测身体是否前倾
        hip_avg_y = (left_hip.y + right_hip.y) / 2
        shoulder_avg_y = (left_shoulder.y + right_shoulder.y) / 2
        qianqingchazhi = hip_avg_y - shoulder_avg_y
        print("身体前倾，请坐直=",qianqingchazhi)
        if qianqingchazhi < 1:  # 前倾阈值
            return "身体前倾，请坐直"

        return "坐姿良好"

    def stop(self):
        """
        停止线程
        """
        self.active = False  # 设置线程停止标志


class ZuozitaoshiWindow(QMainWindow):
    """
    主窗口类，用于显示摄像头画面和操作按钮
    """
    def __init__(self):
        super().__init__()
        self.setWindowTitle("坐姿检测系统")  # 设置窗口标题
        self.setGeometry(100, 100, 800, 600)  # 设置窗口大小和位置

        # 创建布局
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)
        self.layout = QVBoxLayout()
        self.central_widget.setLayout(self.layout)

        # 创建视频显示标签
        self.video_label = QLabel(self)
        self.video_label.resize(640, 480)  # 设置视频显示区域大小
        self.video_label.setAlignment(Qt.AlignCenter)  # 设置内容居中显示
        self.layout.addWidget(self.video_label)

        # 创建状态标签
        self.status_label = QLabel("坐姿状态：", self)
        self.status_label.setAlignment(Qt.AlignCenter)  # 设置文本居中显示
        self.layout.addWidget(self.status_label)

        # 创建按钮
        self.start_button = QPushButton("开始检测", self)
        self.start_button.clicked.connect(self.start_detection)  # 绑定按钮点击事件
        self.layout.addWidget(self.start_button)

        self.stop_button = QPushButton("停止检测", self)
        self.stop_button.clicked.connect(self.stop_detection)  # 绑定按钮点击事件
        self.layout.addWidget(self.stop_button)

        # 初始化后台线程
        self.posture_checker = PostureChecker()
        self.posture_checker.update_frame.connect(self.update_image)  # 绑定图像更新信号
        self.posture_checker.posture_status.connect(self.update_status)  # 绑定坐姿状态更新信号

    def start_detection(self):
        """
        启动坐姿检测线程
        """
        self.posture_checker.active = True
        self.posture_checker.start()

    def stop_detection(self):
        """
        停止坐姿检测线程
        """
        self.posture_checker.stop()

    def update_image(self, cv_img):
        """
        更新视频显示区域的图像
        :param cv_img: 转换为 PyQt 可用的图像格式
        """
        qt_img = QPixmap.fromImage(cv_img)
        self.video_label.setPixmap(qt_img)  # 将图像设置到 QLabel 中

    def update_status(self, status):
        """
        更新坐姿状态显示
        :param status: 坐姿状态描述
        """
        self.status_label.setText(f"坐姿状态：{status}")  # 更新状态标签内容


if __name__ == "__main__":
    app = QApplication(sys.argv)  # 创建 PyQt 应用程序实例
    window = ZuozitaoshiWindow()  # 创建主窗口实例
    window.show()  # 显示窗口
    sys.exit(app.exec_())  # 启动应用程序的主循环